package cn.com.greatwall.user.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import cn.com.greatwall.common.model.Result;
import cn.com.greatwall.common.model.SysMenu;
import cn.com.greatwall.common.service.impl.SuperServiceImpl;
import cn.com.greatwall.user.mapper.SysMenuMapper;
import cn.com.greatwall.user.mapper.SysRoleMenuMapper;
import cn.com.greatwall.user.model.SysRoleMenu;
import cn.com.greatwall.user.service.ISysMenuService;
import cn.com.greatwall.user.service.ISysRoleMenuService;

/**
 * @Author herw
 * @Time 2022-02-19 15:13:59
 * @Version 1.0
 * @Description: TODO(用一句话描述该文件做什么)
 */
@Service
public class SysMenuServiceImpl extends SuperServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
    @Resource
    private ISysRoleMenuService roleMenuService;
    
    @Resource
    private SysRoleMenuMapper roleMenuMapper;
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setMenuToRole(Long roleId, Set<Long> menuIds) {
        roleMenuService.delete(roleId, null);

        if (!CollectionUtils.isEmpty(menuIds)) {
            List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
            menuIds.forEach(menuId -> roleMenus.add(new SysRoleMenu(roleId, menuId)));
            roleMenuService.saveBatch(roleMenus);
        }
    }
    
    /**
     * 角色菜单列表
     * @param roleIds
     * @return
     */
    @Override
    public List<SysMenu> findByRoles(Set<Long> roleIds) {
        return roleMenuService.findMenusByRoleIds(roleIds, null);
    }
    
    /**
     * 角色菜单列表
     * @param roleIds 角色ids
     * @param roleIds 是否菜单
     * @return
     */
    @Override
    public List<SysMenu> findByRoles(Set<Long> roleIds, Integer type) {
        return roleMenuService.findMenusByRoleIds(roleIds, type);
    }
    
    @Override
    public List<SysMenu> findByRoleCodes(Set<String> roleCodes, Integer type) {
        return roleMenuService.findMenusByRoleCodes(roleCodes, type);
    }
    
    /**
     * 查询所有菜单
     */
    @Override
    public List<SysMenu> findAll() {
        return baseMapper.selectList(new QueryWrapper<SysMenu>().orderByAsc("menu_sort"));
    }
    
    /**
     * 查询所有一级菜单
     */
    @Override
    public List<SysMenu> findOnes() {
        return baseMapper.selectList(
                new QueryWrapper<SysMenu>()
                        .in("type", 0, 1)
                        .orderByAsc("menu_sort")
        );
    }
    
    @Override
    public List<SysMenu> findByPid(String pid) {
        return baseMapper.selectList(new QueryWrapper<SysMenu>().eq("pid", pid).orderByAsc("menu_sort"));
    }

    @Override
    public Result saveOrUpdateMenu(SysMenu sysMenu) throws Exception {
        if (sysMenu.getId() == null) {
            // 计算子节点数目
            sysMenu.setSubCount(0);
            saveOrUpdate(sysMenu);
            
            // 更新父节点菜单数目
            updateSubCnt(sysMenu.getPid());
        } else {
            SysMenu menu = baseMapper.selectById(sysMenu.getId());
            // 记录的父节点ID
            Long oldPid = menu.getPid();
            Long newPid = sysMenu.getPid();
            // 计算父级菜单节点数目
            updateSubCnt(oldPid);
            updateSubCnt(newPid);
            
            saveOrUpdate(sysMenu);
        }
        
        return Result.succeed("操作成功");
    }
    
    /**
     * 更新子节点数目
     * 
     * @param menuId
     */
    private void updateSubCnt(Long menuId) {
        if (menuId != null) {
            Long count = baseMapper.selectCount(new QueryWrapper<SysMenu>().eq("pid", menuId));
            baseMapper.updateSubCntById(count, menuId);
        }
    }

    @Override
    public Result delete(Long id) throws Exception {
        List<SysMenu> menuList = findByPid(id.toString());
        Set<SysMenu> menuSet = new HashSet<>();
        menuSet.add(baseMapper.selectById(id));
        menuSet = getChildMenus(menuList, menuSet);
        for (SysMenu menu : menuSet) {
            roleMenuMapper.delete(null, id);
            baseMapper.deleteById(menu.getId());
            updateSubCnt(menu.getPid());
        }
        
        return Result.succeed("操作成功");
    }

    @Override
    public Set<SysMenu> getChildMenus(List<SysMenu> menuList, Set<SysMenu> menuSet) {
        for (SysMenu menu : menuList) {
            menuSet.add(menu);
            List<SysMenu> menus = findByPid(menu.getId().toString());
            if(menus!=null && menus.size()!=0){
                getChildMenus(menus, menuSet);
            }
        }
        return menuSet;
    }

    @Override
    public List<SysMenu> getSuperior(SysMenu menu, List<SysMenu> menus) {
        if (menu.getPid().equals(-1L)) {
            menus.addAll(findOnes());
            return menus;
        }
        menus.addAll(findByPid(menu.getPid().toString()));
        return getSuperior(baseMapper.selectById(menu.getPid()), menus);
    }

    @Override
    public List<SysMenu> getMenus(Long pid) {
        List<SysMenu> menus;
        if (pid != null && !pid.equals(-1L)) {
            menus = findByPid(pid.toString());
        } else {
            menus = findOnes();
        }
        return menus;
    }
}
